#pragma once

#include "../mqcommon/mq_logger.hpp"
#include "../mqcommon/mq_msg.pb.h"

/*
    我们的消费者是以队列为单元进行管理的，当队列收到一条消息后，需要选择一个消费者，通过rr轮转的思想
*/

namespace mq{
    //当队列收到一条消息后，需要选择一个消费者进行消费，那么如何消费呢？
    //就是调用这个回调函数，其内部逻辑是：找到消费者对应的连接，将消息发送给客户端。
    using ConsumerCallBack = std::function<void(const std::string&,const BasicProperties *,const std::string &)>;
    struct Consumer
    {
        using ptr = std::shared_ptr<Consumer>;
        std::string _qname; //消费者订阅的队列名称
        std::string _ctag;  //消费者标识
        bool _auto_ack;  //自动应答标志
        ConsumerCallBack _cb;

        Consumer(){}
        Consumer(const std::string &qname,const std::string &ctag,bool auto_ack,const ConsumerCallBack &cb)
            :_qname(qname),_ctag(ctag),_auto_ack(auto_ack),_cb(cb) {}
    };

    class QueueConsumer
    {
    private:
        std::string _qname; //队列名称
        std::mutex _mutex;  
        uint64_t _rr_sep;   //轮转序号
        std::vector<Consumer::ptr> _consumers;
    public:
    using ptr = std::shared_ptr<QueueConsumer>;
        QueueConsumer(const std::string &qname)
            :_qname(qname),_rr_sep(0) {}

        //新增一个消费者 
        Consumer::ptr create(const std::string &qname,const std::string &ctag,bool auto_ack,const ConsumerCallBack &cb){
            //1.加锁
            std::unique_lock<std::mutex> lock(_mutex);

            //2.判断消费者是否存在
            for(auto &cons : _consumers){
                if(cons->_ctag == ctag){
                    return cons;
                }
            }

            //3.创建消费者并添加管理
            Consumer::ptr csp = std::make_shared<Consumer>(qname,ctag,auto_ack,cb);
            _consumers.push_back(csp);

            return csp;
        }
        //删除一个消费者：取消订阅、信道关闭、连接关闭的时候删除
        void remove(const std::string &ctag){
            //1.加锁
            std::unique_lock<std::mutex> lock(_mutex);

            //2.遍历删除
            for(auto it = _consumers.begin(); it != _consumers.end(); ++it){
                if((*it)->_ctag == ctag){
                    _consumers.erase(it);
                    return;
                }
            }

            return;
        }
        
        //选择一个消费者，rr轮转的思想
        Consumer::ptr choose(){
            //1.加锁
            std::unique_lock<std::mutex> lock(_mutex);

            //如果没有消费者，则返回空对象
            if(_consumers.size() == 0){
                return Consumer::ptr();
            }
            //2.获取当前选择的消费者下标
            uint64_t idx = _rr_sep % _consumers.size();
            _rr_sep++;

            //3.获取对象并返回
            return _consumers[idx];
        }

        //以下接口用于单元测试
        bool empty(){
            std::unique_lock<std::mutex> lock(_mutex);
            return _consumers.size() == 0;
        }
        bool exists(const std::string &ctag){
            std::unique_lock<std::mutex> lock(_mutex);
            for(auto it = _consumers.begin(); it != _consumers.end(); ++it){
                if((*it)->_ctag == ctag){
                    return true;
                }
            }
            return false;
        }
        void clear(){
            std::unique_lock<std::mutex> lock(_mutex);
            _consumers.clear();
        }
    };

    class ConsumerManager
    {
    private:    
        std::mutex _mutex;
        std::unordered_map<std::string,QueueConsumer::ptr> _qconsumers;
    public:
    using ptr = std::shared_ptr<ConsumerManager>;
        ConsumerManager(){}
        //初始化队列消费者管理
        void initQueueConsumer(const std::string &qname){
            //1. 加锁
            std::unique_lock<std::mutex> lock(_mutex);
            //2. 重复判断
            auto it = _qconsumers.find(qname);
            if (it != _qconsumers.end()) {
                return ;
            }
            //3. 新增
            auto qconsumers = std::make_shared<QueueConsumer>(qname);
            _qconsumers.insert(std::make_pair(qname, qconsumers));
        }
        //删除队列消费者管理
        void destroyQueueConsumer(const std::string &qname){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _qconsumers.find(qname);
            if (it == _qconsumers.end()) {
                return ;
            }
            _qconsumers.erase(it);
        }

        Consumer::ptr create(const std::string &qname,const std::string &ctag,bool auto_ack,const ConsumerCallBack &cb){
            QueueConsumer::ptr qcp;
            {
                std::unique_lock<std::mutex> lock(_mutex);

                auto it = _qconsumers.find(qname);
                if(it == _qconsumers.end()){
                    ELOG("没有找到队列 %s 的消费者管理句柄！",qname.c_str());
                    return Consumer::ptr();
                }

                qcp = it->second;
            }

            //这个create不需要我们这里的mutex保护，他有自己的mutex
            return qcp->create(qname,ctag,auto_ack,cb);
        }
        void remove(const std::string &ctag,const std::string &qname){
            QueueConsumer::ptr qcp;
            {
                std::unique_lock<std::mutex> lock(_mutex);

                auto it = _qconsumers.find(qname);
                if(it == _qconsumers.end()){
                    ELOG("没有找到队列 %s 的消费者管理句柄！",qname.c_str());
                    return ;
                }

                qcp = it->second;
            }

            qcp->remove(ctag);
        }

        Consumer::ptr choose(const std::string &qname){
            QueueConsumer::ptr qcp;
            {
                std::unique_lock<std::mutex> lock(_mutex);

                auto it = _qconsumers.find(qname);
                if(it == _qconsumers.end()){
                    ELOG("没有找到队列 %s 的消费者管理句柄！",qname.c_str());
                    return Consumer::ptr();
                }

                qcp = it->second;
            }

            return qcp->choose();
        }
        bool empty(const std::string &qname){
            QueueConsumer::ptr qcp;
            {
                std::unique_lock<std::mutex> lock(_mutex);

                auto it = _qconsumers.find(qname);
                if(it == _qconsumers.end()){
                    ELOG("没有找到队列 %s 的消费者管理句柄！",qname.c_str());
                    return false;
                }

                qcp = it->second;
            }

            return qcp->empty();
        }
        bool exists(const std::string &ctag,const std::string &qname){
            QueueConsumer::ptr qcp;
            {
                std::unique_lock<std::mutex> lock(_mutex);

                auto it = _qconsumers.find(qname);
                if(it == _qconsumers.end()){
                    ELOG("没有找到队列 %s 的消费者管理句柄！",qname.c_str());
                    return false;
                }

                qcp = it->second;
            }

            return qcp->exists(ctag);
        }
        void clear(){
            std::unique_lock<std::mutex> lock(_mutex);
            _qconsumers.clear();
        }
    };
}